package com.hunttown.common.sharding.client.rule;

import com.hunttown.common.sharding.client.config.FunctionRegistry;
import com.hunttown.common.sharding.client.rule.function.Function;

import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.CollectionUtils;

public class DefaultRouteRule implements RouteRule<Object>, InitializingBean {
    private List<Function> tableRouteFuncs;
    private List<Function> dbRouteFuncs;

    public DefaultRouteRule() {
    }

    public void setTableRouteFuncs(List<Object> tableRouteFuncs) {
        this.tableRouteFuncs = this.getFuncs(tableRouteFuncs);
    }

    public List<Function> getDbRouteFuncs() {
        return Collections.unmodifiableList(this.dbRouteFuncs);
    }

    public void setDbRouteFuncs(List<Object> dbRouteFuncs) {
        this.dbRouteFuncs = this.getFuncs(dbRouteFuncs);
    }

    public List<Function> getTableRouteFuncs() {
        return Collections.unmodifiableList(this.tableRouteFuncs);
    }

    public List<Function> getFuncs(List<Object> funcList) {
        if (!CollectionUtils.isEmpty(funcList)) {
            List<Function> funcs = new LinkedList();
            Iterator i$ = funcList.iterator();
            if (i$.hasNext()) {
                Object obj = i$.next();
                if (obj instanceof Function) {
                    funcs.add((Function) obj);
                } else if (obj instanceof String) {
                    Function func = FunctionRegistry.getFunction("hash");
                    if (func == null) {
                        throw new IllegalArgumentException("Unregistered function!name:" + obj);
                    }

                    funcs.add(func);
                }

                throw new IllegalArgumentException("Illegal function parameter!");
            } else {
                return funcs;
            }
        } else {
            return Collections.emptyList();
        }
    }

    public int getDbIndex(Object routeFactor) {
        Long dbIndex = this.funcChain(routeFactor, this.dbRouteFuncs);
        return dbIndex == null ? 0 : Integer.parseInt(String.valueOf(dbIndex));
    }

    public int getTableIndex(Object routeFactor) {
        Long tableIndex = this.funcChain(routeFactor, this.tableRouteFuncs);
        return tableIndex == null ? 0 : Integer.parseInt(String.valueOf(tableIndex));
    }

    protected Long funcChain(Object routeFactor, List<Function> funcs) {
        Long result = null;

        for (int i = 0; i < funcs.size(); ++i) {
            Function func = (Function) funcs.get(i);
            if (i == 0) {
                result = func.process(routeFactor);
            } else {
                result = func.process(result);
            }
        }

        return result;
    }

    public void afterPropertiesSet() throws Exception {
        if (CollectionUtils.isEmpty(this.dbRouteFuncs)) {
            throw new IllegalStateException("dbRouteFuncs cann't be null or empty!");
        } else if (CollectionUtils.isEmpty(this.tableRouteFuncs)) {
            throw new IllegalArgumentException("tableRouteFuncs cann't be null or empty!");
        }
    }
}